feat(sdd,agents): SDD-003 spec-gate + AI-019 model-tier policy#60
Merged
Conversation
Bundle of two logically-distinct changes plus a small ghostty config tweak.
User-elected bundle (against atomic-PR ideal) — conscious deviation, not scope creep.
SDD-003 (Tier 4+5 of the SDD enforcement stack)
- scripts/check-spec-gate.sh: LOC threshold (>=50) + spec-folder presence
check, basename-aware lockfile exclusion (npm/pnpm/go), `skip-sdd` label +
rationale escape hatch, dependabot bypass.
- .github/workflows/spec-gate.yml: pull_request trigger, env-var pattern
(no `${{}}` in run: blocks).
- .github/pull_request_template.md: SDD checklist + skip-rationale header.
- .pre-commit-config.yaml + scripts/install-precommit.sh --with-sdd-gate:
opt-in pre-push hook for local pre-flight.
- tests/check-spec-gate.bats: 16 cases. tests/install-precommit.bats: +4 cases.
AI-019 (cross-agent model-tier policy)
- AGENTS.md: new "Model Selection (Task-Aware)" section between Standing
Orders and Competence Retention Protocol. Top / Mid / Low tiers, trigger
heuristics ("propose, don't force"), per-agent overlay pointers.
- ai/claude/CLAUDE.md, ai/gemini/GEMINI.md, ai/copilot/copilot-instructions.md,
ai/opencode/opencode.jsonc: ~6-line Model Tier subsection each with literal
model IDs (Claude empirical; OpenCode empirical; Gemini + Copilot marked TBD
pending validation).
- tests/opencode.bats: CLAUDE.md threshold bumped 70->80 with inline reason.
terminal/ghostty/config: bell-features=no-system, window-vsync=true (user-authored
session tweaks, bundled at user request).
Specs at specs/SDD-003-ci-spec-gate/ and specs/AI-019-model-tier-policy/.
AUDIT-004 architecture map landed separately in the vault via Hive auto-commit.
Tests: bats 645/645 green; shellcheck --severity=error clean; opencode.jsonc
structurally valid (top-level keys + 5 MCP servers intact); JSON workflow valid.
This was referenced May 20, 2026
mlorentedev
added a commit
that referenced
this pull request
May 26, 2026
…gy, copy-only deploy)
Real bug (integration container under set -u):
- scripts/healthcheck.sh skip() referenced $2 unconditionally. Six callsites
pass only the test name (e.g. agy not in PATH). Fixed via ${2:+ - $2}
optional suffix so single-arg calls no longer abort with "unbound variable".
Windows healthcheck.ps1 parity:
- 12 section labels were stuck on /12 while sec 13 (Antigravity) used /13.
Now all 13 use /13, matching healthcheck.sh and unblocking bats parity test.
- Removed unused $agyData assignment (PSScriptAnalyzer warning).
- Updated synopsis docstring 12 sections -> 13.
Test alignment (no behaviour changes — code was already correct):
- tests/healthcheck-ps1.bats: 12 sections -> 13.
- tests/opencode.bats: default model nan/deepseek-v4-flash -> nan/qwen3.6
(qwen chosen empirically in opencode.jsonc; deepseek is now opt-in via /models).
- tests/opencode.bats: alias oc="opencode --pure" (mirrors .bashrc + profile.ps1).
- tests/powershell-profile.bats: gemini alias -> agy alias (Antigravity migration).
- tests/powershell-profile.bats: oc is now a function (not Set-Alias) so --pure
can be passed. Parity check updated to match function form on Windows and
alias form on POSIX.
- tests/verify-setup.bats: post-SDD-007/BUG-100 the setup deploys via copy
(deploy_file), not symlinks. Tests #20-26, #43, #60 now assert "regular file
AND NOT a symlink" to make the copy-only invariant explicit. Test #33
asserts $HOME/.ssh/config has 600 (the file SSH actually reads), not the
intermediate $DOTFILES_DIR/ssh/config which inherits cp's 644. Test #37
~/.gemini/GEMINI.md -> ~/.gemini/AGY.md per gemini-cli -> agy rename.
mlorentedev
added a commit
that referenced
this pull request
May 26, 2026
…102) * fix(BUG-100): resolve circular symlinks and staging latency in agy 1.0.2 - Implemented flat-file strategy for mcp_config.json to bypass agy recursion bug. - Enforced production endpoint via ANTIGRAVITY_ENDPOINT, CLOUDCODE_URL, and GEMINI_DIR. - Optimized interactive performance: switched to Flash, reduced verbosity, disabled keep_thinking. - Ported all fixes to Windows setup and healthcheck scripts for cross-platform parity. - Updated healthcheck.sh/ps1 with dedicated Antigravity integrity assertions. * feat(SDD-007): NaN as opencode default + IaC deploy + agy schema fix + MCP trim * IaC migration: 9x ln -sf -> deploy_file/Deploy-File (utils.{sh,ps1}) * BUG-100 fix: master MCP config at ~/.gemini/config/, mcpServers schema (per Google gemini-cli docs), no symlinks * NaN community as opencode default (nan/qwen3.6 -- 4x faster than deepseek-v4-flash per scripts/nan-bench.sh; bench shows reasoning chain adds 30-180 tokens silently) * MCP catalog trim across all environments: keep hive + context7 + sequential-thinking. Drop drawio (rare use, spawned subprocess even with --pure) and socket (mcp.socket.dev hung 30s+ blocking responses). * oc alias defaults to 'opencode --pure' (no MCP overhead). ocfull for agentic tool-use. Empirical: full mode hung on complex queries due to 38 tool definitions in system prompt. * New tooling: dbg alias (reasoning visible workaround for opencode TUI which drops non-OpenAI reasoning_content fields), nan-bench, nan-quality-bench, cleanup-legacy-ai.{sh,ps1} * Windows parity: utils.ps1 (Deploy-File/Test-FileDrift), cleanup-legacy-ai.ps1, load-secrets.ps1 (added Add-Secret + Update-Secret) * Drops: agy plugin import gemini, legacy gemini-cli compat write, opencode-go provider, aider aliases * Docs: ai/nan/README.md (provider), ai/opencode/README.md (client pointer) Closes #100 * fix(SDD-007): PSScriptAnalyzer + CI integration secrets soft-source * setup-windows.ps1: rename to in MCP merge loop (PSAvoidAssignmentToAutomaticVariable -- is reserved) * setup-linux.sh: remove speculative agy install URL (not confirmed by upstream); replace with clear manual-install warning * setup-linux.sh: wrap secrets fallback in subshell + soft-source so CI containers without age vault don't trip set -e during MCP consolidation * fix(SDD-007): set-e safe jq pipe + update stale bats assertions * setup-linux.sh: || true on OLD_KEY jq|grep pipe (grep returns 1 on empty input; pipefail propagates; was exiting at MCP consolidation on fresh CI containers without master config yet) * tests/setup-linux.bats: tmux.conf assertion migrated to deploy_file (SDD-007 IaC strategy) * tests/setup-windows.bats: gemini->agy section header, opencode.jsonc expects Deploy-File helper, GEMINI.md->AGY.md pointer marker * fix(SDD-007): Windows-parity AGY.md deploy + verify (Neural Hive pointer) setup-windows.ps1 was missing the AGY.md copy + 'First, read AGENTS.md' pointer verification that setup-linux.sh ran at line 407-413. Adds it right before the Gemini prompts sync block to match Linux ordering. Test in setup-windows.bats updated to assert the pointer marker is present in BOTH setup scripts (cross-OS parity). * fix(SDD-007): CI test gates + .bashrc drift tolerance * setup-linux.sh: .bashrc drops strict check_deployed (tool installers legitimately append PATH/init lines; check existence only) * tests/aliases.bats: oc alias regex now matches both 'opencode' and 'opencode --pure' (SDD-007 default flipped to --pure) * tests/antigravity.bats: setup() skips suite when agy not installed (CI containers don't have agy; these are integration-style tests) * fix(SDD-007): rename GEMINI_HOME->AGY_HOME in tests + section count 12->13 env-contract.json already uses AGY_HOME (set in PR #97); tests/env-contract.bats still referenced the old GEMINI_HOME name. healthcheck.sh has 13 sections after Antigravity Health was added; tests still asserted 12-section count. * tests/env-contract.bats: sed GEMINI_HOME -> AGY_HOME (10 refs) * tests/healthcheck.bats: section count 12 -> 13 (tmux 9/13, ghostty 11/13, drift 12/13, antigravity 13/13) * setup-windows.ps1: post-install summary now shows 'Antigravity: AGY.md' instead of the stale 'Gemini config: GEMINI.md' (legacy artifact) * fix(SDD-007): pre-export AGY_HOME + healthcheck test counts (12->13) * setup-{linux.sh,windows.ps1}: pre-export AGY_HOME alongside GEMINI_HOME in the REFACTOR-002 path-var block (env-contract.json declares AGY_HOME as the SSOT name; GEMINI_HOME kept for backward compat) * tests/healthcheck.bats: section count 12 -> 13 (Antigravity section was added in PR #98); tmux assertion now checks check_deployed instead of readlink (post-IaC migration: tmux.conf is copied, not symlinked) * fix(SDD-007): suppress shellcheck SC2016 false-positive on literal $schema match healthcheck.sh:362 uses single-quoted regex '"\$schema":' to match the literal '$schema' JSON key in opencode.jsonc -- no expansion intended. Shellcheck SC2016 flags as 'did you mean to expand?' (info). Suppress inline so tests/healthcheck.bats:51 (shellcheck-must-pass) stays green on stricter CI shellcheck versions. * fix(SDD-007): CI green — skip() bug + parity fixes (12->13, gemini->agy, copy-only deploy) Real bug (integration container under set -u): - scripts/healthcheck.sh skip() referenced $2 unconditionally. Six callsites pass only the test name (e.g. agy not in PATH). Fixed via ${2:+ - $2} optional suffix so single-arg calls no longer abort with "unbound variable". Windows healthcheck.ps1 parity: - 12 section labels were stuck on /12 while sec 13 (Antigravity) used /13. Now all 13 use /13, matching healthcheck.sh and unblocking bats parity test. - Removed unused $agyData assignment (PSScriptAnalyzer warning). - Updated synopsis docstring 12 sections -> 13. Test alignment (no behaviour changes — code was already correct): - tests/healthcheck-ps1.bats: 12 sections -> 13. - tests/opencode.bats: default model nan/deepseek-v4-flash -> nan/qwen3.6 (qwen chosen empirically in opencode.jsonc; deepseek is now opt-in via /models). - tests/opencode.bats: alias oc="opencode --pure" (mirrors .bashrc + profile.ps1). - tests/powershell-profile.bats: gemini alias -> agy alias (Antigravity migration). - tests/powershell-profile.bats: oc is now a function (not Set-Alias) so --pure can be passed. Parity check updated to match function form on Windows and alias form on POSIX. - tests/verify-setup.bats: post-SDD-007/BUG-100 the setup deploys via copy (deploy_file), not symlinks. Tests #20-26, #43, #60 now assert "regular file AND NOT a symlink" to make the copy-only invariant explicit. Test #33 asserts $HOME/.ssh/config has 600 (the file SSH actually reads), not the intermediate $DOTFILES_DIR/ssh/config which inherits cp's 644. Test #37 ~/.gemini/GEMINI.md -> ~/.gemini/AGY.md per gemini-cli -> agy rename. * fix(SDD-007): finish 12->13 renumber in healthcheck-ps1.bats per-section tests Previous commit missed the inline per-section assertions (tests #190-205): - The loop iterating 1..12 over Write-Section labels (line 64). - 12 per-section assertions hardcoding the /12 denominator (lines 73-118). - 3 SKIP/drift assertions referencing /12 (lines 123, 127, 131-138). All now match the .ps1 labels (1/13..13/13). Added missing assertion for section 13/13 (Antigravity CLI Health, SDD-007).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two logically-distinct changes bundled by user decision (against atomic-PR ideal — conscious deviation, not scope creep) plus a small ghostty config tweak the user authored mid-session.
AGENTS.mdwith per-agent overlay pointers carrying the literal model IDs (Top / Mid / Low tiers, "propose-don't-force" trigger heuristics).terminal/ghostty/configgainsbell-features=no-system+window-vsync=true(user-authored).SDD checklist
SDD-003-ci-spec-gate,AI-019-model-tier-policy,AUDIT-004-architecture-map)specs/SDD-003-ci-spec-gate/andspecs/AI-019-model-tier-policy/proposal.mdfilled for both (Why / What / Acceptance criteria / Risks)tasks.mdin TDD order for bothverification.mdfilled for both with evidence + test outputsfeatures.json(SDD-003) tracks 13 features inpendingstate pre-mergeSDD skip rationale
Test plan
bats tests/*.bats→ 645/645 pass (16 new SDD-003 cases + 4 new install-precommit cases)shellcheck --severity=error scripts/*.sh setup-linux.shcleanpython3JSONC validation onai/opencode/opencode.jsonc(top-level keys + 5 MCP servers intact)python3 -c "import yaml; yaml.safe_load(...)"on.github/workflows/spec-gate.ymlcleanspecs/<feature-id>/folders → expected to PASS the spec-gate (case B)Notable decisions
origin/main; pre-commit would falsely fail intermediate WIP commits during red-green-refactor.//comments instead of_modelTierCommentJSON key — the file already uses//extensively; adding the model-tier block as comments is diff-friendly and avoids polluting the parsed JSON namespace.tests/opencode.bats(model-tier addition is intentional cross-agent consistency, not slippage).Out of scope (for future PRs)
verification.md; ADR-010 is the natural sibling)Companion vault artifact
30-architecture/dotfiles-architecture-map.md(AUDIT-004) landed in the vault via Hive auto-commit ahead of this PR. Two Mermaid diagrams (setup-time + runtime data flow) + 23-row "where does X live" reference table — used as baseline for the queued AUDIT-001/002/003.